package com.xgk.boot.module.core.service.channel;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.service.impl.DiffParseFunction;
import com.mzt.logapi.starter.annotation.LogRecord;
import com.xgk.boot.framework.common.enums.CommonStatusEnum;
import com.xgk.boot.framework.common.pojo.PageResult;
import com.xgk.boot.framework.common.util.object.BeanUtils;
import com.xgk.boot.module.core.controller.admin.channel.vo.sp.SpApiRelaReqVO;
import com.xgk.boot.module.core.controller.admin.channel.vo.sp.SpPageReqVO;
import com.xgk.boot.module.core.controller.admin.channel.vo.sp.SpSaveReqVO;
import com.xgk.boot.module.core.controller.admin.channel.vo.sp.SpSelectNode;
import com.xgk.boot.module.core.dal.entity.channel.ApiServiceDO;
import com.xgk.boot.module.core.dal.entity.channel.ServiceProviderDO;
import com.xgk.boot.module.core.dal.entity.channel.SpApiRelaDO;
import com.xgk.boot.module.core.dal.iservice.ServiceProviderService;
import com.xgk.boot.module.core.dal.mapper.channel.ApiServiceMapper;
import com.xgk.boot.module.core.dal.mapper.channel.ServiceProviderMapper;
import com.xgk.boot.module.core.dal.mapper.channel.SpApiRelaMapper;
import com.xgk.boot.module.core.dal.redis.RedisKeyConstants;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.C;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static com.xgk.boot.framework.common.constant.ErrorCodeConstants.*;
import static com.xgk.boot.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.xgk.boot.module.core.enums.LogRecordConstants.*;

@Slf4j
@Service
public class ServiceProviderServiceImpl extends ServiceImpl<ServiceProviderMapper, ServiceProviderDO> implements ServiceProviderService {

    @Resource
    private ServiceProviderMapper serviceProviderMapper;
    @Resource
    private ApiServiceMapper apiServiceMapper;
    @Resource
    private SpApiRelaMapper spApiRelaMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @LogRecord(type = SYSTEM_SP_TYPE, subType = SYSTEM_SP_CREATE_TYPE, bizNo = "{{#sp.spId}}", success = SYSTEM_SP_CREATE_SUCCESS)
    public Long createSp(SpSaveReqVO createReqVO) {

//        ApiServiceDO apiServiceDO = apiServiceMapper.selectById(createReqVO.getAsId());
//        if(apiServiceDO ==null){
//            throw exception(API_NOT_EXISTS, createReqVO.getAsId());
//        }
        validateSpDuplicate(createReqVO.getSpName(), createReqVO.getSpCode());

        ServiceProviderDO api = BeanUtils.toBean(createReqVO, ServiceProviderDO.class);
        serviceProviderMapper.insert(api);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable("sp", api);
        return api.getSpId();
    }

    private void validateSpDuplicate(String name, String code) {
        ServiceProviderDO api = serviceProviderMapper.selectByName(name);
        if(api != null) {
            throw exception(SP_EXISTS, name);
        }
        if(!StringUtils.hasText(code)) {
            return;
        }
        api = serviceProviderMapper.selectByCode(code);
        if(api != null) {
            throw exception(SP_CODE_DUPLICATE, code);
        }
    }

    @Override
    @LogRecord(type = SYSTEM_SP_TYPE, subType = SYSTEM_SP_UPDATE_TYPE, bizNo = "{{#updateReqVO.asId}}", success = SYSTEM_SP_UPDATE_SUCCESS)
    @CacheEvict(cacheNames = RedisKeyConstants.SERVICE_PROVIDER, key = "#updateReqVO.spId")
    public void updateSp(SpSaveReqVO updateReqVO) {
        ServiceProviderDO api = validateSpForUpdate(updateReqVO.getSpId());
//        validateSpDuplicate(updateReqVO.getAsName(),updateReqVO.getAsCode());
        ServiceProviderDO updateObj = BeanUtils.toBean(updateReqVO, ServiceProviderDO.class);
        updateObj.setSpCode(null);
        serviceProviderMapper.updateById(updateObj);

        // 3. 记录操作日志上下文
        LogRecordContext.putVariable(DiffParseFunction.OLD_OBJECT, BeanUtils.toBean(api, SpSaveReqVO.class));
        LogRecordContext.putVariable("api", api);
    }

    ServiceProviderDO validateSpForUpdate(Long id) {
        ServiceProviderDO api = serviceProviderMapper.selectById(id);
        if(api == null) {
            throw exception(SP_NOT_EXISTS);
        }

        return api;
    }

    @Override
    public PageResult<ServiceProviderDO> getSpPage(SpPageReqVO pageReqVO) {
        PageResult<ServiceProviderDO> result = serviceProviderMapper.selectPage(pageReqVO);
        result.setPageParam(pageReqVO);
        return result;
    }

    @CacheEvict(cacheNames = RedisKeyConstants.SERVICE_PROVIDER, key = "#spId")
    @Override
    public void activeSp(Long spId, Integer asStatus) {
        ServiceProviderDO api = validateSpForUpdate(spId);
        if(asStatus == CommonStatusEnum.ENABLE.getStatus()) {
            api.setSpStatus(CommonStatusEnum.DISABLE.getStatus());
        } else {
            api.setSpStatus(CommonStatusEnum.ENABLE.getStatus());
        }
        serviceProviderMapper.updateById(api);
    }

    /**
     * 通过id获取供应商信息
     * @return
     */
    @Cacheable(cacheNames = RedisKeyConstants.SERVICE_PROVIDER, key = "#spId", unless = "#result == null")
    public ServiceProviderDO getSpById(Long spId) {
        ServiceProviderDO api = serviceProviderMapper.selectById(spId);
        if(api == null) {
            log.error("ServiceProvider not exists, spId: {}", spId);
            throw exception(SP_NOT_EXISTS);
        }
        return api;
    }

    @Override
    public List<ServiceProviderDO> getSpSelectList() {
        List<ServiceProviderDO> all = serviceProviderMapper.selectList(ServiceProviderDO::getSpStatus, CommonStatusEnum.ENABLE.getStatus());
        return all;
    }

    @Override
    public PageResult<ApiServiceDO> queryApiRelations(SpApiRelaReqVO pageReqVO) {
        List<ApiServiceDO> result = apiServiceMapper.selectBySpId(pageReqVO.getSpId());
        PageResult<ApiServiceDO> paged = new PageResult(result, Long.valueOf(result.size()));
        paged.setPageParam(pageReqVO);
        return paged;
    }

    @Override
    public boolean unbindApi(Long spId, Long asId) {
        return spApiRelaMapper.delete(new LambdaQueryWrapper<SpApiRelaDO>().eq(SpApiRelaDO::getSpId, spId).eq(SpApiRelaDO::getAsId, asId)) > 0;
    }

    @Override
    public boolean bindApi(Long spId, Long asId) {
        SpApiRelaDO rela = new SpApiRelaDO();
        rela.setSpId(spId);
        rela.setAsId(asId);
        return spApiRelaMapper.insert(rela) > 0;
    }

    @Override
    public List<ApiServiceDO> getApiSelectListNotInSp(Long spId) {
        List<ApiServiceDO> result = apiServiceMapper.getApiSelectListNotInSp(spId);
        return result;
    }

    public List<SpSelectNode> buildProviderTree() {
        // 1. 查询所有有效供应商
        List<ServiceProviderDO> providers = serviceProviderMapper.selectList(
                new LambdaQueryWrapper<ServiceProviderDO>()
                        .eq(ServiceProviderDO::getSpStatus, CommonStatusEnum.ENABLE.getStatus())
        );

        // 2. 构建树形结构
        return providers.stream().map(provider -> {
            // 创建供应商节点
            SpSelectNode providerNode = SpSelectNode.buildProviderNode(provider);

            // 构建父节点链 (当前只有供应商ID)
            List<String> parentChain = Collections.singletonList(providerNode.getId());

            // 查询该供应商关联的API
            List<ApiServiceDO> apis = apiServiceMapper.selectApisByProviderId(provider.getSpId());

            // 添加API子节点
            apis.stream()
                    .filter(api -> api.getAsStatus() == CommonStatusEnum.ENABLE.getStatus())
                    .map(api -> SpSelectNode.buildApiNode(
                            api,
                            providerNode.getPath(), // 父级路径
                            parentChain              // 父节点ID链
                    ))
                    .forEach(providerNode.getChildren()::add);

            return providerNode;
        }).collect(Collectors.toList());
    }
}
